// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "VideoSocketAgent.h"
#include <thread>
#include "VideoAgent.h"
#include "EncoderPoolClient/client_common.h"
#include "EncoderPoolClient/RrConfig.h"

std::shared_ptr<VideoSocketAgent> VideoSocketAgent::g_videoSockAgentInstance = nullptr;
std::mutex VideoSocketAgent::g_instanceLock;
VideoSocketAgent::Garbo VideoSocketAgent::g_garbo;

/**
 * @功能描述：Garbo析构函数,删除单例g_instance
 */
VideoSocketAgent::Garbo::~Garbo()
{
    if (VideoSocketAgent::g_videoSockAgentInstance != nullptr) {
        VideoSocketAgent::g_videoSockAgentInstance = nullptr;
    }
}

/**
 * @功能描述：ServerNotice构造函数
 */
ServerNotice::ServerNotice() {}

/**
 * @功能描述：ServerNotice虚析构函数
 */
ServerNotice::~ServerNotice() {}

/**
 * @功能描述：服务器监听socket异常回调通知，Agent执行退出流程
 * @参数 [in] socket：服务端socket
 */
void ServerNotice::Notice(std::shared_ptr<VmiSocket> socket)
{
    if (socket != nullptr) {
        ERR("ServerNotice-----%p", socket.get());
    }
    VideoAgent::GetInstance()->Exit();
}

/**
 * @功能描述：VmiClientService构造函数
 */
VmiClientService::VmiClientService() {}

/**
 * @功能描述：VmiClientService析构函数
 */
VmiClientService::~VmiClientService() {}

/**
 * @功能描述：TCP服务端有新socket连接上时回调函数
 * @参数 [in] socket：新连接的客户端socket
 */
void VmiClientService::Callback(std::shared_ptr<VmiSocket> socket)
{
    INFO("VmiClientService callback");
    VideoSocketAgent::GetInstance()->SetClientSocket(socket);
    return;
}

/**
 * @功能描述：VideoSocketAgent的构造函数
 */
/*lint -save -e1401 */
VideoSocketAgent::VideoSocketAgent()
{
}
/*lint -restore */
/**
 * @功能描述：VideoSocketAgent的析构函数
 */
VideoSocketAgent::~VideoSocketAgent()
{
}

uint32_t VideoSocketAgent::EncodeParamHandleHook(uint8_t* data, uint32_t length)
{
    VideoData videoData(VMIMsgType::VideoEncodeConf, data, length);
    VideoSocketAgent::GetInstance()->AddVideoData(videoData);
    return 0;
}

/*
 * @功能描述：GL数据处理钩子函数
 * @参数 [in] data：数据地址
 * @参数 [in] length：数据大小
 * @返回值：成功返回0，失败返回1
 */
uint32_t VideoSocketAgent::YuvHandleHook(uint8_t* data, uint32_t length)
{
    VideoData videoData(VMIMsgType::VideoStreamYuv, data, length);
    VideoSocketAgent::GetInstance()->AddVideoData(videoData);
    return 0;
}

/**
 * @功能描述：启动TCP服务端,WebSocket服务器监听
 * @返回值：true代表启动socket server成功， failed代表失败
 */
bool VideoSocketAgent::StartServer(int port)
{
    m_serverNotive = std::make_shared<ServerNotice>();
    m_clientService = std::make_shared<VmiClientService>();

    INFO("Listen to private ip : %s", rr::gClientConfig.iSocketWorker.ipAddr.c_str());
    m_serverSocket = new (std::nothrow) VmiTcpServerSocket(inet_network(rr::gClientConfig.iSocketWorker.ipAddr.c_str()),
        port, std::dynamic_pointer_cast<VmiServerService>(m_clientService));
    if (m_serverSocket != nullptr) {
        m_serverSocket->SetEventNotice(std::dynamic_pointer_cast<VmiEventNotice>(m_serverNotive));
        if (m_serverSocket->Start() == 0) {
            INFO("start TCP server successfully");
        } else {
            ERR("error: start TCP server failed!");
            return false;
        }
    } else {
        ERR("Fatal error: new TCP server failed!");
        return false;
    }

    return true;
}

/**
 * @功能描述：重置VideoSocketAgent对象为初始态
 */
void VideoSocketAgent::Reset()
{
    std::unique_lock<std::mutex> lockGuard(m_lock);
    Reset(m_videoagentComm);
}

/**
 * @功能描述：重置VideoSocketAgent对象为初始态
 */
void VideoSocketAgent::Reset(std::shared_ptr<NetComm> breakComm)
{
    INFO("VideoSocketAgent Reset");

    if (breakComm == nullptr) {
        return;
    }
    if (breakComm.get() == m_videoagentComm.get()) {
        m_sendFlag = false;
        if (m_videoagentComm != nullptr) {
            m_videoagentComm->Deinit();
            m_videoagentComm = nullptr;
        }
        if (m_videoEncoder != nullptr) {
            m_videoEncoder->ForceStop();
            m_videoEncoder = nullptr;
            INFO("m_videoEncoder destroy done");
        }
        ClearVideoData();
    }

    rr::gClientConfig.status = ENCODE_POOL_WORKER_IDLE;
    gClientInfo.reportStatus(rr::gClientConfig.status);
    INFO("VideoSocketAgent Reset out");
}

/**
    * @功能描述：设置新socket的连接, 初始化netCom
    */
bool VideoSocketAgent::StartNewClient(std::shared_ptr<VmiSocket> newSocket)
{
    m_videoagentComm = std::shared_ptr<NetComm>(new NetComm(
        newSocket, [](std::shared_ptr<NetComm> breakComm) -> void {
        VideoSocketAgent::GetInstance()->HandleSocketBreak(breakComm);
    }));
    if (m_videoagentComm == nullptr) {
        ERR("create videoagent comm failed");
        return false;
    }
    if (!m_videoagentComm->Init()) {
        ERR("init videoagent comm failed");
        m_videoagentComm->Deinit();
        m_videoagentComm = nullptr;
        return false;
    }
    uint32_t ret = m_videoagentComm->RegisterHook(VMIMsgType::VideoEncodeConf, EncodeParamHandleHook, true);
    if (ret != VMI_SUCCESS) {
        ERR("RegisterHook failed");
        return false;
    }
    ret = m_videoagentComm->RegisterHook(VMIMsgType::VideoStreamYuv, YuvHandleHook, true);
    if (ret != VMI_SUCCESS) {
        ERR("RegisterHook failed");
        return false;
    }
    m_videoagentComm->SetSingleFragment(VMIMsgType::VideoStreamH264, true);
    if (!m_videoagentComm->Start()) {
        ERR("start videoagent comm failed");
        m_videoagentComm->Deinit();
        m_videoagentComm = nullptr;
        return false;
    }
    m_videoEncoder = std::shared_ptr<VideoEncoder>(new VideoEncoder(
    []() -> void {
    INFO("video encode engine reset");
    VideoSocketAgent::GetInstance()->Reset();
    }));
    if (m_videoEncoder ==nullptr) {
        ERR("failed to malloc");
    }
    if (!m_videoEncoder->Start()) {
        ERR("videoEncoder start failed");
        return false;
    }
    //EnableSend();
    m_sendFlag = true;
    rr::gClientConfig.status = ENCODE_POOL_WORKER_BUSY;
    gClientInfo.reportStatus(rr::gClientConfig.status);
    return true;
}

/**
 * @功能描述：直接进行处理，不再进行客户端client设置
 * @参数 [in] socket：VmiAgent的socket对象
 */
void VideoSocketAgent::SetClientSocket(std::shared_ptr<VmiSocket> VideoSocket)
{
    std::unique_lock<std::mutex> lockGuard(m_lock);
    if (VideoSocket != nullptr) {
        INFO("new VideoSocket");
        if (m_videoagentComm != nullptr) {
            WARN("Existing a connect, new client try to connect refused!");
            return;
        }
        INFO("new socket AgentEventNotice");
        if (VideoAgent::GetInstance()->AgentEventNotice(VideoAgent::VIDEO_AGENT_EVENT_ACCEPT) != true) {
            ERR("tcp socket VIDEO_AGENT_EVENT_ACCEPT failed");
            VideoSocket = nullptr;
            return;
        }
        if (!StartNewClient(VideoSocket)) {
            ERR("Start new client failed");
            return;
        }
    } else {
        ERR("ERROR: Current socket is nullptr");
        return;
    }
}

/**
 * @功能描述：VideoSocketAgent的单例函数
 */
std::shared_ptr<VideoSocketAgent> VideoSocketAgent::GetInstance()
{
    if (g_videoSockAgentInstance == nullptr) {
        std::unique_lock<std::mutex> lockGuard(g_instanceLock);
        if (g_videoSockAgentInstance == nullptr) {
            g_videoSockAgentInstance = std::make_shared<VideoSocketAgent>();
            if (g_videoSockAgentInstance == nullptr) {
                ERR("VideoSocketAgent new failed");
            }
        }
    }
    return g_videoSockAgentInstance;
}

/**
 * @功能描述：VideoSocketAgent的单例销毁函数
 */
void VideoSocketAgent::CloseInstance()
{
    if (g_videoSockAgentInstance != nullptr) {
        g_videoSockAgentInstance = nullptr;
    }
}

/**
 * @功能描述：处理SOCKET中断事件
 */
void VideoSocketAgent::HandleSocketBreak(std::shared_ptr<NetComm> breakComm)
{
    INFO("HandleSocketBreak in..........");
    std::unique_lock<std::mutex> lockGuard(m_lock);
    if (breakComm.get() == m_videoagentComm.get()) {
        if (VideoAgent::GetInstance()->AgentEventNotice(VideoAgent::VIDEO_AGENT_EVENT_BREAK) == true) {
            Reset(breakComm);
        }
    }
}

/**
 * @功能描述：设置m_sendFlag变量为true。当调用Send函数时使能socket发送
 */
void VideoSocketAgent::EnableSend()
{
    INFO("Enable send flag...");
    std::unique_lock<std::mutex> lockGuard(m_lock);
    m_sendFlag = true;
}

/**
 * @功能描述：设置m_sendFlag变量为false。当调用Send函数时禁用socket发送
 */
void VideoSocketAgent::DisableSend()
{
    INFO("DisableSend in......");
    std::unique_lock<std::mutex> lockGuard(m_lock);
    m_sendFlag = false;
}

/**
 * @功能描述：VideoSocketAgent的socket发送函数。根据m_sendFlag标志可能不发送真正数据
 * @参数 [in] type：消息包类型
 * @参数 [in] pPkt：消息包头指针
 * @参数 [in] dataSize：消息包类型
 * @参数 [out] 参数名：消息包体大小
 * @返回值：返回已发送的数据大小
 */
int VideoSocketAgent::Send(VMIMsgType type, StreamMsgHead& pPkt, int dataSize)
{
    int ret = 0;

    if (m_videoagentComm != nullptr && m_sendFlag == true) {
        ret = m_videoagentComm->Send(type, pPkt, dataSize);
    } else {
        ret = dataSize;
    }
    return ret;
}

VideoData VideoSocketAgent::GetNextVideoData()
{
    std::unique_lock<std::mutex> lockGuard(m_queueMutex);
    VideoData videoData;
    if (!m_videoDataQueue.empty()) {
        videoData = m_videoDataQueue.front();
        m_videoDataQueue.pop();
    }
    return videoData;
}

void VideoSocketAgent::ClearVideoData()
{
    std::unique_lock<std::mutex> lockGuard(m_queueMutex);
    while (!m_videoDataQueue.empty()) {
        VideoData videoData = m_videoDataQueue.front();
        VmiFreeBuffer(videoData.data);
        m_videoDataQueue.pop();
    }
}

void VideoSocketAgent::AddVideoData(VideoData &videoData)
{
    std::unique_lock<std::mutex> lockGuard(m_queueMutex);
    m_videoDataQueue.push(videoData);
}
